package game;

import static org.lwjgl.opengl.GL11.GL_QUADS;
import static org.lwjgl.opengl.GL11.glBegin;
import static org.lwjgl.opengl.GL11.glColor3f;
import static org.lwjgl.opengl.GL11.glEnd;
import static org.lwjgl.opengl.GL11.glVertex2i;

import java.io.Serializable;

import interfaces.IDrawable;
import application.RunnableComponent;
import application.messages.Message;
import application.messages.commands.ConsoleCommand;
import application.messages.commands.GameCommand;
import data.DataManager;

/**
 * Implements game.
 * 
 * @author Tomas Zima, Drahomir Karchnak
 */
public class Game extends RunnableComponent implements IDrawable, Serializable
{
	/**
	 * Constructor.
	 */
	public Game()
	{
		//
	}

	/**
	 * Redraws game.
	 */
	public void redraw()
	{
		// Redraw world if exists
		if (world != null)
		{
			// world (map, entities etc).
			world.cameraX = world.getPlayerPosition().x;
			world.cameraY = world.getPlayerPosition().y;
			
			world.updateTime(!isActive());
			world.redraw();
			
			// redraw inventory
			Inventory.getInstance().redraw();
			
			// redraw lives indicator
			livesIndicator.redraw();
		}
		// draw some background if it doesn't exists
		else
		{
			glBegin(GL_QUADS);
				glColor3f(0.0f, 0.0f, 0.5f);
				glVertex2i(0, 0);
				glVertex2i(1024, 0);
				
				glColor3f(0.0f, 0.0f, 1.0f);
				glVertex2i(1024, 768);
				glVertex2i(0, 768);
			glEnd();
		}
	}

	/**
	 * Called when game is activated.
	 */
	@Override
	protected void onActivation()
	{
		//
	}

	/**
	 * Called when game is deactivated.
	 */
	@Override
	protected void onDeactivation()
	{
		//
	}
	
	public void testSetBlockType(DataManager.BlockType type)
	{
		this.lastType = type;
	}

	/**
	 * Catch message and do specified action. If this message
	 * is not addressed to the Game component, it will be
	 * sent to the World.
	 */
	@Override
	public void enterNewMessage(Message message)
	{
		// save coordinates of the mouse
		int x = message.position.x;
		int y = message.position.y;

		/*
		 * Some messages might be caught and sent to the
		 * World anyway.
		 */
		switch ((GameCommand) message.command)
		{
			case PLACE_NEW_BLOCK:
				if (world != null)
				{
					world.testRightMouseClick(x, y, lastType);
				}

				break;
				
			case REMOVE_BLOCK:
				if (world != null)
				{
					world.testLeftMouseClick(x, y);
				}
				
				break;
				
			case PLAYER_MOVE_LEFT:
				if (world != null)
				{
					if (!world.isPlayerInCollision())
					{
						world.enterNewMessage(message);
					}
					world.cameraX -= 8;
				}
		
				break;
				
			case PLAYER_MOVE_RIGHT:
				if (world != null)
				{
					if (!world.isPlayerInCollision())
					{
						world.enterNewMessage(message);
					}
					world.cameraX += 8;
				}
				
				break;
				
			case PLAYER_MOVE_UP:
				if (world != null)
				{
					if (!world.isPlayerInCollision())
					{
						world.cameraY -= 8;
					}
					world.enterNewMessage(message);					
				}
				
				break;
				
			case PLAYER_MOVE_DOWN:
				if (world != null)
				{
					if (!world.isPlayerInCollision())
					{
						world.cameraY += 8;
					}
					world.enterNewMessage(message);					
				}
				
				break;
			
			case SYSTEM_CREATE_WORLD:
				this.world = new World();
				break;
				
			default:
				if (world != null)
				{
					world.enterNewMessage(message);
				}
				
				break;
		}
	}
	
	public void enterNewConsoleCommand(Message message)
	{
		switch ((ConsoleCommand) message.command)
		{
			default:
				world.enterNewConsoleCommand(message);
				break;
		}
	}
	
	/**
	 * Checks if world was already created or not.
	 *
	 * @return
	 * 	True: world was created, false: world wasn't created
	 */
	public boolean isWorldCreated()
	{
		if (world == null)
		{
			return false;
		}
		else
		{
			return true;
		}
	}
	
	/**
	 * Moves by objects based on time from last iteration.
	 * 
	 * @param deltaTime
	 */
	public void update(long deltaTime)
	{
		if (world != null)
		{
			world.update(deltaTime);
			livesIndicator.setLives(world.getPlayersLives());
		}
	}
	
	// Reference to all worlds in the game
	private World			world;
	private LivesIndicator	livesIndicator = new LivesIndicator();
	
	public DataManager.BlockType lastType = DataManager.BlockType.BLOCK_DIRT;
}
